package cn.edu.neu.lab603.cloudeval.monitor

import cn.edu.neu.lab603.cloudeval.CloudEval
import cn.edu.neu.lab603.cloudeval.entity.{DataCenter, PhysicalMachine}
import cn.edu.neu.lab603.des.{SimMetric, SimMonitor}

import scala.collection.mutable

/** 数据中心饱和度的计算方式。
  * 基本思想：计算机的能耗在某一个区间内运行下，效果是最佳的。较高的资源利用率会导致竞争，而较低的资源利用率会导致浪费。
  *
  * Created by yfwz100 on 2016/11/5.
  */
class ResSaturateMetric(resSpanMap: Map[String, (Double, Double)]) extends SimMonitor[CloudEval] {

  private val values = new mutable.ListBuffer[Double]

  override def isMatch(context: CloudEval): Boolean = context.getCurrentTask.isInstanceOf[DataCenter.UpdateEvent]

  override def before(context: CloudEval): Unit = {}

  override def after(context: CloudEval): Unit = {
    values += context.dataCenters.map { dc =>
      val runningHosts = dc.pmList.filter(_.getStatus == PhysicalMachine.Status.ON)
      if (runningHosts.nonEmpty) {
        runningHosts.count(_.getUsedResPct.forall { p =>
          val (k, u) = p
          val (min, max) = resSpanMap(k)
          u >= min && u <= max
        }).toDouble / runningHosts.size
      } else 0.0
    }.sum / context.dataCenters.size
  }

  /** 获取平均饱和度。 */
  lazy val getAverageMetric = new SimMetric[Double] {
    override def getCurrentValue: Double = values.sum / values.size
  }

  /** 获取最后一次获得的饱和度。 */
  lazy val getLastMetric = new SimMetric[Double] {
    override def getCurrentValue: Double = values.last
  }
}
